#include "userprog/syscall.h"
#include <stdio.h>
#include <syscall-nr.h>
#include "threads/interrupt.h"
#include "threads/thread.h"
#include "userprog/process.h"
#include "filesys/file.h"
#include "threads/synch.h"
#define STDIN 0
#define STDOUT 1
#define STDERR 2
/* This is a skeleton system call handler */

static void syscall_handler (struct intr_frame *);

struct semaphore mutex;

void
syscall_init (void) 
{
  intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
}

static void
syscall_handler (struct intr_frame *f UNUSED) 
{
	//PRJ4 Modified
	uint32_t arg1, arg2, arg3;
	int syscall_num = *(int *) f->esp;
	uint32_t* eax = &(f->eax);
	switch(syscall_num){
    		case SYS_HALT:
			
			break;
    		case SYS_EXIT:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_EXEC:
			retrieve(&(f->esp), 1, &arg1);
			*eax = process_execute((char*) arg1);
			break;
    		case SYS_WAIT:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_CREATE:
			retrieve(&(f->esp), 1, &arg1);
			retrieve(&(f->esp), 2, &arg2);
			break;
    		case SYS_REMOVE:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_OPEN:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_FILESIZE:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_READ:
			retrieve(&(f->esp), 1, &arg1);
			retrieve(&(f->esp), 2, &arg2);
			retrieve(&(f->esp), 3, &arg3);
			if((int) arg1 == STDIN)
				*eax  = (uint32_t) input_getc();			
			break;
    		case SYS_WRITE:
			retrieve(&(f->esp), 1, &arg1);
			retrieve(&(f->esp), 2, &arg2);
			retrieve(&(f->esp), 3, &arg3);
			if((int) arg1 == STDOUT){
				//sema_down(&mutex);
				putbuf((const char *) arg2, (size_t) arg3);	
				//sema_up(&mutex);
			}		
			break;
    		case SYS_SEEK:
			retrieve(&(f->esp), 1, &arg1);
			retrieve(&(f->esp), 2, &arg2);
			break;
    		case SYS_TELL:
			retrieve(&(f->esp), 1, &arg1);
			break;
    		case SYS_CLOSE:
			retrieve(&(f->esp), 1, &arg1);
			break;
		default:
			break;
	}
	//by HJ
  //printf ("system call!\n");
  thread_exit ();
}
void retrieve(void** esp, int num, uint32_t* ret)
{
	*ret = *(*(uint32_t**)esp + num);
}
